﻿using Serilog;
using Spectre.Console;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace WorkTool.Helpers
{
    public static class UpdateHelper
    {
        private const string UPDATE_SHARE_PATH = @"\\SZO-23-P03\code";

        private const string MAIN_EXE_NAME = "WorkTool.exe";

        private const string UPDATE_EXE_NAME = "Update.exe";

        private static VersionInfo _versionInfo = null;

        private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
        {
            // PropertyNamingPolicy = JsonNamingPolicy.CamelCase,//驼峰
            ReferenceHandler = ReferenceHandler.IgnoreCycles,//忽略循环引用
            IncludeFields = true,//包含成员字段序列化
            PropertyNameCaseInsensitive = true,//不区分大小写
            AllowTrailingCommas = true,//允许尾随逗号
            ReadCommentHandling = JsonCommentHandling.Skip,//允许注释
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,//处理乱码问题
            WriteIndented = true,//是否应使用整齐打印
        };

        public static void Update()
        {
            // 检查更新
            if (CheckForUpdate())
            {
                var ynOptions = new List<(int Index, string Description)>{
                    new (1, "是"),
                    new (0, "否")
                };
                var selection = AnsiConsole.Prompt(new SelectionPrompt<(int Index, string Description)>()
                                .Title($"[green1]发现新版本【{_versionInfo.Version}】！是否立即更新？{(string.IsNullOrEmpty(_versionInfo.Message) ? "" : $"\n本次更新内容：\n{_versionInfo.Message}")}[/]")
                                .PageSize(10)
                                .UseConverter(option => $"[yellow]【{option.Description}】[/]")
                                .AddChoices(ynOptions));
                switch (selection.Index)
                {
                    case 0:
                        break;

                    case 1:
                        AnsiConsole.MarkupLine("[green1]正在更新中...[/]");
                        StartUpdater();
                        break;

                    default:
                        break;
                }
                return;
            }
        }

        private static bool CheckForUpdate()
        {
            try
            {
                var latestVersionPath = Path.Combine(UPDATE_SHARE_PATH, "version.txt");
                var latestVersionStr = File.ReadAllText(latestVersionPath).Trim();
                _versionInfo = JsonSerializer.Deserialize<VersionInfo>(latestVersionStr, _jsonSerializerOptions);
                var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
                var latestVersion = new Version(_versionInfo.Version);
                return latestVersion > currentVersion;
            }
            catch (Exception ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException)
            {
                Log.Error(ex, "更新服务器未找到或无法访问。");
                return false;
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                return false;
            }
        }

        private static void StartUpdater()
        {
            var remoteZipPath = Path.Combine(UPDATE_SHARE_PATH, _versionInfo.FileName);
            var startInfo = new ProcessStartInfo(UPDATE_EXE_NAME)
            {
                Arguments = $"\"{remoteZipPath}\" \"{MAIN_EXE_NAME}\"",
                UseShellExecute = true
            };
            try
            {
                Process.Start(startInfo);
                Environment.Exit(0); // 立即退出主程序
            }
            catch (Exception ex)
            {
                Log.Error(ex, "无法启动更新程序");
                Console.ReadLine();
            }
        }

        private static readonly JsonDocumentOptions _jsonDocumentOptions = new()
        {
            AllowTrailingCommas = true,
            CommentHandling = JsonCommentHandling.Skip
        };

        private static readonly JsonWriterOptions _jsonWriterOptions = new()
        {
            Indented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        };

        /// <summary>
        /// 将b.json的结构更新到a.json，保留a.json中已有的值
        /// </summary>
        /// <param name="aPath">a.json文件路径</param>
        /// <param name="bPath">b.json文件路径</param>
        public static void UpdateSetting(string aPath, string bPath)
        {
            // 读取a.json和b.json内容
            string aJson = File.ReadAllText(aPath);
            string bJson = File.ReadAllText(bPath);

            // 解析为JSON文档
            using JsonDocument aDoc = JsonDocument.Parse(aJson, _jsonDocumentOptions);
            using JsonDocument bDoc = JsonDocument.Parse(bJson, _jsonDocumentOptions);

            // 合并结构（以b的结构为基准，保留a的值）
            JsonElement merged = MergeElements(aDoc.RootElement, bDoc.RootElement);

            // 将合并结果写回a.json
            string mergedJson = JsonSerializer.Serialize(merged, _jsonSerializerOptions);
            File.WriteAllText(aPath, mergedJson, Encoding.UTF8);
        }

        /// <summary>
        /// 递归合并两个JSON元素，保留a的值，按b的结构调整
        /// </summary>
        private static JsonElement MergeElements(JsonElement a, JsonElement b)
        {
            // 情况1：b是对象，优先按对象合并
            if (b.ValueKind == JsonValueKind.Object)
            {
                using var memoryStream = new MemoryStream();
                using (var writer = new Utf8JsonWriter(memoryStream, _jsonWriterOptions))
                {
                    writer.WriteStartObject();

                    // 先处理b中的所有键（保证结构与b一致）
                    foreach (var bProp in b.EnumerateObject())
                    {
                        string propName = bProp.Name;
                        JsonElement bValue = bProp.Value;

                        // 如果a中存在该键，则递归合并值；否则直接使用b的值
                        if (a.TryGetProperty(propName, out JsonElement aValue))
                        {
                            JsonElement mergedValue = MergeElements(aValue, bValue);
                            writer.WritePropertyName(propName);
                            mergedValue.WriteTo(writer);
                        }
                        else
                        {
                            // a中没有该键，直接添加b的键值
                            bProp.WriteTo(writer);
                        }
                    }

                    writer.WriteEndObject();
                }

                // 将内存流中的数据解析为JsonElement
                memoryStream.Position = 0;
                using var mergedDoc = JsonDocument.Parse(memoryStream, _jsonDocumentOptions);
                return mergedDoc.RootElement.Clone();
            }

            // 情况2：b是数组，a是对象（完善的对象转数组处理）
            if (b.ValueKind == JsonValueKind.Array && a.ValueKind == JsonValueKind.Object)
            {
                using var memoryStream = new MemoryStream();
                using (var writer = new Utf8JsonWriter(memoryStream, _jsonWriterOptions))
                {
                    writer.WriteStartArray();

                    // 获取b数组中的所有元素
                    var bElements = b.EnumerateArray().ToList();

                    JsonElement mergedElement = MergeElements(a, bElements[0]);
                    mergedElement.WriteTo(writer);

                    writer.WriteEndArray();
                }

                memoryStream.Position = 0;
                using var mergedDoc = JsonDocument.Parse(memoryStream, _jsonDocumentOptions);
                return mergedDoc.RootElement.Clone();
            }

            // 情况3：b是数组，a也是数组（完善的数组元素合并逻辑）
            if (b.ValueKind == JsonValueKind.Array && a.ValueKind == JsonValueKind.Array)
            {
                using var memoryStream = new MemoryStream();
                using (var writer = new Utf8JsonWriter(memoryStream, _jsonWriterOptions))
                {
                    writer.WriteStartArray();

                    // 先处理到两个数组中长度较短的那个的长度
                    var aElements = a.EnumerateArray().ToList();
                    var bElements = b.EnumerateArray().ToList();

                    // 合并对应索引的元素
                    for (int i = 0; i < aElements.Count; i++)
                    {
                        if (bElements.Count > 0)
                        {
                            JsonElement mergedElement = MergeElements(aElements[i], bElements[0]);
                            mergedElement.WriteTo(writer);
                        }
                        else
                        {
                            aElements[i].WriteTo(writer);
                        }
                    }

                    writer.WriteEndArray();
                }

                memoryStream.Position = 0;
                using var mergedDoc = JsonDocument.Parse(memoryStream, _jsonDocumentOptions);
                return mergedDoc.RootElement.Clone();
            }

            // 情况4：其他类型（如字符串、数字等），保留a的值（不被b覆盖）
            return a.ValueKind != JsonValueKind.Undefined ? a.Clone() : b.Clone();
        }
    }

    public class VersionInfo
    {
        /// <summary>
        /// 版本号
        /// </summary>
        public string Version { get; set; }

        /// <summary>
        /// 文件名称
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// 更新描述
        /// </summary>
        public string Message { get; set; }
    }
}